//
//  AppDelegate.swift
//  chat
//
//  Created by 崔世强 on 2018/9/17.
//  Copyright © 2018年 崔世强. All rights reserved.
//

import UIKit
import SwiftyUserDefaults
import UserNotifications
import CloudPushSDK
import TrustKit
import Kingfisher

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
    
    // 移动推送appkey和secret
    let pushAppKey = "334761549"
    let pushAppSecret = "7c79f657d6b9423eb74852fbc6b2e0d8"
    
    var window: UIWindow?
    
    func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        let Defaults = UserDefaults(suiteName: "group.missle-chat")!
        
        guard let userId = Defaults[.userId],let userName = Defaults[.username] else {
            return true
        }
        
        AppStatusManager.instance.avatarPath = Defaults[.userAvatar]
        AppStatusManager.instance.userLoginStatus = (true,userId,userName)
        UIView.appearance().tintColor = UIColor(named: "AccentColor")
        UITableView.appearance().backgroundColor = UIColor(named: "chat_bg")
        return true
    }
    
    
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
//        initSSLPining()
        
        self.window = UIWindow(frame: UIScreen.main.bounds)
        let tab = ChatTabBarController()
        self.window?.rootViewController = AppStatusManager.instance.userLoginStatus.0 ? tab : UserViewController()
        self.window?.makeKeyAndVisible()
        
        
        // APNs注册，获取deviceToken并上报
        registerAPNs(application)
        // 初始化阿里云推送SDK
        initCloudPushSDK()
        // 监听推送通道打开动作
        listenOnChannelOpened()
        // 监听推送消息到达
        registerMessageReceive()
        // 点击通知将App从关闭状态启动时，将通知打开回执上报
        //CloudPushSDK.handleLaunching(launchOptions)(Deprecated from v1.8.1)
        CloudPushSDK.sendNotificationAck(launchOptions)
        application.applicationIconBadgeNumber = 0;
        CloudPushSDK.syncBadgeNum(0) { _ in }
        
        ImageCache.default.diskStorage.config.expiration = .never
        
        return true
    }
    
    func initSSLPining() {
        let trustKitConfig = [
            kTSKSwizzleNetworkDelegates: true,
            kTSKPinnedDomains: [
                "shiqiang.com": [
                    kTSKPublicKeyHashes: [
                        "sss6QjeYEQ8SSPqPw6DIMLn9Chj0EhGdikcVxtAkqc0=",
                        "sss6QjeYEQ8SSPqPw6DIMLn9Chj0EhGdikcVxtAaqc0="
                    ],
                    kTSKEnforcePinning: true,
                    kTSKIncludeSubdomains: true
                ]
            ]
        ] as [String : Any]
        
        TrustKit.initSharedInstance(withConfiguration:trustKitConfig)
    }
    
    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
    }
    
    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
        ConnectionManager.instance.disconnect()
    }
    
    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
        application.applicationIconBadgeNumber = 0
        CloudPushSDK.syncBadgeNum(0, withCallback: {_ in })
    }
    
    func applicationDidBecomeActive(_ application: UIApplication) {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
        //TODO 可以考虑使用Notification的方式
        if AppStatusManager.instance.userLoginStatus.0 {
            ConnectionManager.instance.connect()
        }
    }
    
    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    }
    
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        completionHandler(UNNotificationPresentationOptions.sound)
    }
    
    func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) async {
        UIApplication.shared.applicationIconBadgeNumber = 0
        CloudPushSDK.sendNotificationAck(response.notification.request.content.userInfo)
    }
    
    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
        CloudPushSDK.registerDevice(deviceToken) { callbackResult in
            if let callbackResult = callbackResult, callbackResult.success {
                UserDefaults.standard.setValue(deviceToken.map { String(format: "%02.2hhx", arguments: [$0]) }.joined(), forKey: "deviceToken")
                print("成功注册device token: \(deviceToken.map { String(format: "%02.2hhx", arguments: [$0]) }.joined())")
            } else {
                print("注册device token失败: \(deviceToken.map { String(format: "%02.2hhx", arguments: [$0]) }.joined())")
                print("Register deviceToken failed, error: \(callbackResult?.error)")
            }
        }
    }
    
    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) async -> UIBackgroundFetchResult {
        // 通知打开回执上报
        application.applicationIconBadgeNumber = 0
        CloudPushSDK.sendNotificationAck(userInfo)
        return .noData
    }
    
    
    // 向APNs注册，获取deviceToken用于推送
        func registerAPNs(_ application: UIApplication) {
            // iOS 10+
            let center = UNUserNotificationCenter.current()
            // 创建category，并注册到通知中心
            createCustomNotificationCategory()
            center.delegate = self
            // 请求推送权限
            center.requestAuthorization(options: [.alert, .badge, .sound], completionHandler: { (granted, error) in
                if (granted) {
                    // User authored notification
                    print("User authored notification.")
                    // 向APNs注册，获取deviceToken
                    DispatchQueue.main.async {
                        application.registerForRemoteNotifications()
                    }
                } else {
                    // User denied notification
                    print("User denied notification.")
                }
            })
        }

        // 创建自定义category，并注册到通知中心
        @available(iOS 10, *)
        func createCustomNotificationCategory() {
            let action1 = UNNotificationAction.init(identifier: "action1", title: "test1", options: [])
            let action2 = UNNotificationAction.init(identifier: "action2", title: "test2", options: [])
            let category = UNNotificationCategory.init(identifier: "test_category", actions: [action1, action2], intentIdentifiers: [], options: UNNotificationCategoryOptions.customDismissAction)
            UNUserNotificationCenter.current().setNotificationCategories([category])
        }
        
        // 初始化推送SDK
        func initCloudPushSDK() {
            // 打开Log，线上建议关闭
            CloudPushSDK.turnOnDebug()
            CloudPushSDK.asyncInit(pushAppKey, appSecret: pushAppSecret) { (res) in
                if (res!.success) {
                    print("Push SDK init success, deviceId: \(CloudPushSDK.getDeviceId()!)")
                    let userId = AppStatusManager.instance.userLoginStatus.1
                    CloudPushSDK.bindAccount(String(userId ?? 0), withCallback: {_ in })
                } else {
                    print("Push SDK init failed, error: \(res!.error!).")
                }
            }
        }
        
        // 监听推送通道是否打开
        func listenOnChannelOpened() {
            let notificationName = Notification.Name("CCPDidChannelConnectedSuccess")
            NotificationCenter.default.addObserver(self,
                                                   selector: #selector(channelOpenedFunc(notification:)),
                                                   name: notificationName,
                                                   object: nil)
        }
        
        @objc func channelOpenedFunc(notification : Notification) {
            print("Push SDK channel opened.")
        }
        
        // 注册消息到来监听
        func registerMessageReceive() {
            let notificationName = Notification.Name("CCPDidReceiveMessageNotification")
            NotificationCenter.default.addObserver(self,
                                                   selector: #selector(onMessageReceivedFunc(notification:)),
                                                   name: notificationName,
                                                   object: nil)
        }
        
        // 处理推送消息
        @objc func onMessageReceivedFunc(notification : Notification) {
            print("Receive one message.")
            let pushMessage: CCPSysMessage = notification.object as! CCPSysMessage
            let title = String.init(data: pushMessage.title, encoding: String.Encoding.utf8)
            let body = String.init(data: pushMessage.body, encoding: String.Encoding.utf8)
            print("Message title: \(title!), body: \(body!).")
        }
    
}

